﻿using System;
using System.Collections.Generic;
using Engine;
using Game;
using GameEntitySystem;
using TemplatesDatabase;

namespace Mekiasm
{
    public class ComponentNLevel : Component, IUpdateable
    {
        public struct Factor
        {
            public string Description;

            public float Value;
        }

        public bool maked = false;

        public Game.Random m_random = new Game.Random();

        public ComponentHealth ComponentHealth;

        public ComponentBody Body;

        public static string fName = "ComponentLevel";

        public List<Factor> m_factors = new List<Factor>();

        public ComponentLocomotion Locomotion;

        public ComponentCreature ComponentCreature;

        public float? m_lastLevelTextValue;

        public SubsystemGameInfo m_subsystemGameInfo;

        public SubsystemAudio m_subsystemAudio;

        public SubsystemTime m_subsystemTime;

        public SubsystemShadows subsystemShadows;

        public float Level;

        public float StrengthFactor
        {
            get;
            set;
        }

        public float ResilienceFactor
        {
            get;
            set;
        }
        public float MaxHealthFactor
        {
            get;
            set;
        }
        public float SpeedFactor
        {
            get;
            set;
        }

        public float HungerFactor
        {
            get;
            set;
        }
        public float DefendFactor
        {
            get;
            set;
        }
        public float WalkSpeed = 0f;

        public float FlySpeed = 0f;

        public float SwimSpeed = 0f;

        public SubsystemModelsRenderer m_subsystemModelsRenderer;

        public UpdateOrder UpdateOrder => UpdateOrder.Default;

        public void AddExperience(int count, bool playSound)
        {
            if (ILibrary.SubsystemSky.MoonPhase == 0 || ILibrary.SubsystemSky.MoonPhase == 4) count *= 2;
            for (int i = 0; i < count; i++)
            {
                float num = 0.03f / MathUtils.Pow(1.08f, MathUtils.Floor(Level - 1f));
                Level += num;
            }
        }
        //攻击力系数1f - 100f
        public float CalculateStrengthFactor()
        {
            return 1f + (MathUtils.Clamp(Level, 1f, 999f) - 1) / 10f;
        }
        //生命值系数1f - 100f
        public float CalculateResilienceFactor()
        {
            return 1f + (MathUtils.Clamp(Level, 1f, 999f) - 1) / 10f;
        }
        //速度系数1f - 3f
        public float CalculateSpeedFactor()
        {
            return 1f + (MathUtils.Clamp(Level, 1f, 999f) - 1) / 500f;
        }
        //减伤系数0.04f - 0.80f
        public float CalculateDefendFactor()
        {
            return Level / (Level + 249);
        }
        public void UpdateLevelByTime(double v)
        {
            int num = (int)(v / 180);
            while (num-- > 0) AddExperience(1, false);
        }
        public void Update(float dt)
        {
            if (m_subsystemTime.PeriodicGameTimeEvent(5.0, 1.0))
            {
                AddExperience(1, playSound: false);
            }
            if (Locomotion != null)
            {
                Locomotion.WalkSpeed = Math.Min(WalkSpeed * SpeedFactor, 8f);
                Locomotion.FlySpeed = Math.Min(FlySpeed * SpeedFactor, 8f);
                Locomotion.SwimSpeed = Math.Min(SwimSpeed * SpeedFactor, 8f);
            }

            StrengthFactor = CalculateStrengthFactor();
            SpeedFactor = CalculateSpeedFactor();
            ResilienceFactor = CalculateResilienceFactor();
            DefendFactor = CalculateDefendFactor();

            ComponentHealth.AttackResilienceFactor = ResilienceFactor;
            ComponentHealth.FireResilienceFactor = ResilienceFactor;
            ComponentHealth.FallResilienceFactor = ResilienceFactor;
            ComponentHealth.HealFactor = StrengthFactor;

            bool contain = subsystemParticles.ContainsParticleSystem(fire);

            if (contain) fire.m_position = NormalPosition(ComponentCreature.ComponentBody);

            //高等级增加火焰效果
            if (Level > 200 && ComponentCreature.ComponentHealth.Health > 0 && !contain)
            {
                subsystemParticles.AddParticleSystem(fire);
            }

            if (ComponentCreature.ComponentHealth.Health <= 0 && contain) subsystemParticles.RemoveParticleSystem(fire);
        }

        private SubsystemParticles subsystemParticles;

        private LevelParticleSystem fire;

        private Vector3 NormalPosition(ComponentBody body)
        {
            Vector3 v = body.BoundingBox.Center();
            return v;
        }

        public override void Load(ValuesDictionary valuesDictionary, IdToEntityMap idToEntityMap)
        {
            subsystemParticles = Project.FindSubsystem<SubsystemParticles>();
            m_subsystemGameInfo = Project.FindSubsystem<SubsystemGameInfo>(throwOnError: true);
            m_subsystemTime = Project.FindSubsystem<SubsystemTime>(throwOnError: true);
            m_subsystemAudio = Project.FindSubsystem<SubsystemAudio>(throwOnError: true);
            ComponentCreature = Entity.FindComponent<ComponentCreature>();
            ComponentHealth = Entity.FindComponent<ComponentHealth>();
            Level = valuesDictionary.GetValue("Level", 1f);
            maked = valuesDictionary.GetValue("m", false);
            if (!maked)
            {
                //根据时间随机等级
                //每天增加4级上限
                Level = m_random.Float(1f, MathUtils.Clamp(1f, (float)(m_subsystemGameInfo.TotalElapsedGameTime / 1200f), 999f));
                maked = true;
            }
            StrengthFactor = 1f;
            SpeedFactor = 1f;
            HungerFactor = 1f;
            ResilienceFactor = 1f;
            m_subsystemModelsRenderer = Project.FindSubsystem<SubsystemModelsRenderer>();
            subsystemShadows = Project.FindSubsystem<SubsystemShadows>();
            Locomotion = Entity.FindComponent<ComponentLocomotion>();
            Body = Entity.FindComponent<ComponentBody>();
            if (Locomotion != null)
            {
                WalkSpeed = Locomotion.WalkSpeed;
                FlySpeed = Locomotion.FlySpeed;
                SwimSpeed = Locomotion.SwimSpeed;
                fire = new LevelParticleSystem(NormalPosition(ComponentCreature.ComponentBody),Color.Red, 0.5f, 128f);
                
            }
        }
        public override void Save(ValuesDictionary valuesDictionary, EntityToIdMap entityToIdMap)
        {
            valuesDictionary.SetValue("Level", Level);
            valuesDictionary.SetValue("m", maked);
        }

    }
}